package cn.spike.rockcc.service.impl;

import cn.spike.rockcc.domain.KillActivity;
import cn.spike.rockcc.domain.KillCourse;
import cn.spike.rockcc.dto.RedisOrderDto;
import cn.spike.rockcc.errorenum.GlobalExceptionCode;
import cn.spike.rockcc.mapper.KillCourseMapper;
import cn.spike.rockcc.service.IKillActivityService;
import cn.spike.rockcc.service.IKillCourseService;
import cn.spike.rockcc.util.AssertUtil;
import cn.spike.rockcc.util.CodeGenerateUtils;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author spike
 * @since 2023-03-25
 */
@Service
public class KillCourseServiceImpl extends ServiceImpl<KillCourseMapper, KillCourse> implements IKillCourseService {

    @Autowired
    private IKillActivityService killActivityService;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 将课程加入秒杀
     * @param killCourse
     */
    @Override
    @Transactional
    public void addKill(KillCourse killCourse) {
        KillActivity killActivity = killActivityService.selectById(killCourse.getActivityId());
        AssertUtil.isNotNull(killActivity, GlobalExceptionCode.ACTIVITY_EXCEPTION);
        killCourse.setCreateTime(new Date());
        killCourse.setStartTime(killActivity.getBeginTime());
        killCourse.setEndTime(killActivity.getEndTime());
        killCourse.setPublishStatus(KillCourse.PUBLISH_WAIT);
        killCourse.setTimeStr(killActivity.getTimeStr());
        super.insert(killCourse);
    }

    /**
     * 获取所有发布的秒杀课程
     * @return
     */
    @Override
    public List<KillCourse> getPublishedKill() {
        //取出redis中hash结构存储的 key值为activity:*格式的key
        Set<Object> keys = redisTemplate.keys("activity:*");
        List<KillCourse> killCourses = new ArrayList<>();
        for (Object key : keys) {
            //获取每一个key的值
            List values = redisTemplate.opsForHash().values(key);
            killCourses.addAll(values);
        }
        return killCourses;
    }

    /**
     * 获取单个秒杀课程业务
     * @param killId
     * @param activeId
     * @return
     */
    @Override
    public KillCourse getOnlineOne(Long killId, Long activeId) {
        Object o = redisTemplate.opsForHash().get("activity:" + activeId.toString(), killId.toString());
        AssertUtil.isNotNull(o,GlobalExceptionCode.KILL_COURSE_EXCEPTION);
        return (KillCourse)o;
    }

    /**
     * 秒杀课程点击购买后的业务
     * @param map killCourseId , activityId
     * @return
     */
    @Override
    public String kill(Map<String, String> map) {
        //查看是否有该秒杀课程
        String killCourseId = map.get("killCourseId");
        String activityId = map.get("activityId");
        Object o = redisTemplate.opsForHash().get("activity:" + activityId, killCourseId);
        AssertUtil.isNotNull(o,GlobalExceptionCode.KILL_COURSE_EXCEPTION);
        KillCourse killCourse = (KillCourse) o;
        /**
         * 将用户的购买记录存放在reids中
         *  key:kill:userId:killCourseId
         *  value:orderNo
         */
        //查看用户是否只购买了一次
        Long userId = 3L;   //TODO
        Object userBuyKill = redisTemplate.opsForValue().get("kill:" + userId + ":" + killCourseId);
        //AssertUtil.isNull(userBuyKill,GlobalExceptionCode.RE_BUY_KILL_EXCEPTION);

        //判断是否还有库存 - 如果有就减一如果没有就响应前端
        RSemaphore semaphore = redissonClient.getSemaphore(killCourseId);
        boolean tryAcquire = semaphore.tryAcquire(1);
        AssertUtil.isTrue(tryAcquire,GlobalExceptionCode.NOT_HAVE_KUCUN);

        //  private BigDecimal amount;
        //    private Long courseId;
        //    private String orderNo;
        //    private Long killCourseId;
        //    private Integer orderType;
        //    private Long userId;
        //创建预订单 对象
        String orderNo = CodeGenerateUtils.generateOrderSn(userId);
        RedisOrderDto redisOrderDto = new RedisOrderDto(
                killCourse.getKillPrice(),
                killCourse.getCourseId(),
                orderNo,
                killCourse.getId(),
                RedisOrderDto.KILL_ORDER,
                userId
        );

        //将预订单和用户购买记录存放redis
        /**
         * 将用户的购买记录存放在reids中
         *  key:kill:userId:killCourseId
         *  value:orderNo
         */
        redisTemplate.opsForValue().set("kill:"+userId+":"+killCourseId,orderNo);
        redisTemplate.opsForValue().set(orderNo,redisOrderDto);
        return orderNo;
    }

}
